var SimpleTemplate = function(options){
	var baseOptions = options || {};
	var cache = {};
	var getCacheId = function(id, doc){ return (doc || document).location.pathname + (doc || document).location.search +"@"+ id; };
	var setCache = function(id, value, doc){ cache[getCacheId(id, doc)] = value; };
	var getCache = function(id, doc){ return cache[getCacheId(id, doc)]; };
	var hasCache = function(id, doc){ return cache[getCacheId(id, doc)] != null; };
	var trim = function(s){ return s.replace(/^\s+|\s+$/g, ""); };
	var escape = function(s){ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;") };
	var unescape = function(s){ return s.replace(/&quot;/g, "\"").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&amp;/g, "&"); };
	var firstElement = function(html){
		var e = document.createElement("div");
		e.innerHTML = html;
		for(var i = 0, c = e.childNodes; i < c.length; i++){
			if(c[i].nodeType == 1) return c[i];
		}
		throw "no element";
	};
	var $ = function(id, doc){
		var e = (doc || document).getElementById(id);
		if(e == null) throw "element by id["+ id +"] not found"; else return e;
	};
	var contains = function(list, value){
		for(var i = 0; i < list.length; i++){
			if(list[i] == value) return true;
		}
		return false;
	};
	var evalEx = function(__str, __context){
		with(__context || {}) return eval(__str);
	};
	var forceString = function(s){ return s === undefined ? "undefined" : s === null ? "null" : s.toString(); };
	var getErrorString = function(e){
		if(e instanceof Error){
			var out = "";
			for(var i in e){
				if(i == "stack") continue;
				out += i +":"+ e[i] +", ";
			}
			return out;
		}else return forceString(e);
	}
	var AddonString = function(str){
		var i = str.indexOf(":");
		this.name = (i == -1) ? trim(str) : trim(str.substring(0, i));
		this.args = (i == -1) ? "[]" : "["+ str.substring(i + 1) +"]";
	};
	var AddonChain = function(){
		this.length = 0;
		this.push = function(value){
			if(value != null) this[this.length++] = value;
			return this;
		}
		this.get = function(name){
			for(var i = 0; i < this.length; i++){
				if(name in this[i]) return this[i][name];
			}
			throw "addon["+ name +"] not found";
		}
	};
	var addCatch = function(f, fcatch){
		f["catch"] = fcatch;
		return f;
	};
	var addon = {
		"default":function(target, value){ return (target != null && target.toString().length > 0) ? target : value; },
		"defaultIfEmpty":function(target, value){ return addon["default"](target, value); },
		"defaultIfE":function(target, value){ return addon["default"](target, value); },
		"defaultIfBlank":function(target, value){ return (target != null && trim(target.toString()).length > 0) ? target : value; },
		"defaultIfB":function(target, value){ return addon["defaultIfBlank"](target, value); },
		"defaultIfNull":function(target, value){ return target !== null ? target : value; },
		"defaultIfN":function(target, value){ return addon["defaultIfNull"](target, value); },
		"defaultIfUndefined":function(target, value){ return target !== undefined ? target : value; },
		"defaultIfU":function(target, value){ return addon["defaultIfUndefined"](target, value); },
		"defaultIfNullUndefined":function(target, value){ return target != null ? target : value; },
		"defaultIfNU":function(target, value){ return addon["defaultIfNullUndefined"](target, value); },
		"empty":function(target){ return ""; },
		"emptyIfNull":function(target){ return addon["defaultIfNull"](target, ""); },
		"emptyIfN":function(target){ return addon["emptyIfNull"](target); },
		"emptyIfUndefined":function(target){ return addon["defaultIfUndefined"](target, ""); },
		"emptyIfU":function(target){ return addon["emptyIfUndefined"](target); },
		"emptyIfNullUndefined":function(target){ return addon["defaultIfNullUndefined"](target, ""); },
		"emptyIfNU":function(target){ return addon["emptyIfNullUndefined"](target); },
		"escape":function(target){ return target == null ? target : escape(target.toString()); },
		"unescape":function(target){ return target == null ? target : unescape(target.toString()); },
		"trim":function(target){ return target == null ? target : trim(target.toString()); },
		"ifError":addCatch(function(target){ return target; }, function(e, value){ return value; }),
		"ignoreError":addCatch(function(target){ return target; }, function(e){ return ""; }),
		"forceString":function(target){ return forceString(target); }
	};
	this.parse = function(target, context, options){
		options = options || {};
		var getOption = function(property, validList, defaultVal){
			return contains(validList, options[property]) ? options[property] : contains(validList, baseOptions[property]) ? baseOptions[property] : defaultVal;
		};
		var parseError = getOption("parseError", ["output", "throw"], "throw");
		try{
			var left = options.left || baseOptions.left || "\\$#";
			var right = options.right || baseOptions.right || "#";
			var separator = options.separator || baseOptions.separator || "@";
			var input = getOption("input", ["html", "element", "id"], "id");
			var output = getOption("output", ["element", "html"], "html");
			var evalError = getOption("evalError", ["throw", "output"], "output");
			var doc = options.document || baseOptions.document || document;
			var une = getOption("unescape", ["html", "template"], "template");
			var chain = new AddonChain().push(options.addon).push(baseOptions.addon).push(addon);
			
			if(input == "id") var html = hasCache(target, doc) ? getCache(target, doc) : $(target, doc).innerHTML;
			else if(input == "element") var html = target.innerHTML;
			else var html = target;
			
			var resultHtml = (une == "html" ? unescape(html) : html).replace(new RegExp(left +"([\\s\\S]*?)"+ right, "g"), function(str, content){
				var items = (une == "html" ? content : unescape(content)).split(separator);
				
				try{
					var result = evalEx(items[0], context);
				}catch(e){
					var error = e;
				}
				for(var i = 1; i < items.length; i++){
					var a = new AddonString(items[i]);
					var func = chain.get(a.name);
					try{
						if(error == null) result = func.apply(context, [result].concat(evalEx(a.args, context)));
						else if("catch" in func){
							result = func["catch"].apply(context, [error].concat(evalEx(a.args, context)));
							error = null;
						}
					}catch(e){
						var error = e;
					}
				}
				if(error != null){
					if(evalError == "output") return getErrorString(error); else throw error;
				}
				return forceString(result);
			});
			
			return output == "html" ? resultHtml : firstElement(resultHtml);
		}catch(e){
			if(parseError == "output") return getErrorString(e); else throw e;
		}
	};
	this.readElementAndRemoveChildren = function(id, doc){
		var e = this.readElement(id, doc);
		for(var c = e.childNodes, i = c.length -1; i >= 0; i--){
			e.removeChild(c[i]);
		}
		return e;
	};
	this.readAndRemoveElement = function(id, doc){
		var e = this.readElement(id, doc);
		return e.parentNode.removeChild(e);
	};
	this.readElement = function(id, doc){
		var e = $(id, doc);
		setCache(id, e.innerHTML, doc);
		return e;
	};
};
/* simple-template (ver. 1.0.2) [MIT License] (c) 2008 a7user:gnety */